﻿//-----------------------------------------------------------------------------
// Copyright (c) 2010 Anders Liu
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace AndersLiu.Bambook.Sdk
{
    /// <summary>
    /// 对Bambook核心类库的封装。
    /// </summary>
    public static class Bambook
    {
        /// <remarks>
        /// #define BAMBOOK_SDK_VERSION 0x00090000
        /// </remarks>
        public const int BAMBOOK_SDK_VERSION_09 = 0x00090000;

        /// <remarks>
        /// #define DEFAULT_BAMBOOK_IP  "192.168.250.2"
        /// </remarks>
        public const string DEFAULT_BAMBOOK_IP = "192.168.250.2";

        /// <remarks>
        /// #define BR_SUCC             0     // 操作成功
        /// #define BR_FAIL             1001  // 操作失败
        /// #define BR_NOT_IMPL         1002  // 该功能还未实现
        /// #define BR_DISCONNECTED     1003  // 与设备的连接已断开
        /// #define BR_PARAM_ERROR      1004  // 调用函数传入的参数错误
        /// #define BR_TIMEOUT          1005  // 操作或通讯超时
        /// #define BR_INVALID_HANDLE   1006  // 传入的句柄无效
        /// #define BR_INVALID_FILE     1007  // 传入的文件不存在或格式无效
        /// #define BR_INVALID_DIR      1008  // 传入的目录不存在
        /// #define BR_BUSY             1010  // 设备忙，另一个操作还未完成
        /// #define BR_EOF              1011  // 文件或操作已结束
        /// #define BR_IO_ERROR         1012  // 文件读写失败
        /// #define BR_FILE_NOT_INSIDE  1013  // 指定的文件不在包里
        /// </remarks>
        public enum Result
        {
            Success = 0,
            Fail = 1001,
            NotImplemented = 1002,
            Disconnected = 1003,
            ParameterError = 1004,
            Timeout = 1005,
            InvalidHandle = 1006,
            InvalidFile = 1007,
            InvalidDirectory = 1008,
            Busy = 1010,
            EndOfFile = 1011,
            IOError = 1012,
            FileNotInside = 1013,
        }

        /// <remarks>
        /// #define CONN_CONNECTED      0     // 已连接
        /// #define CONN_DISCONNECTED   1     // 未连接或连接已断开
        /// #define CONN_CONNECTING     2     // 正在连接
        /// #define CONN_WAIT_FOR_AUTH  3     // 已连接，正在等待身份验证（暂未实现）
        /// </remarks>
        public enum ConnectionState
        {
            Connected = 0,
            Disconnected = 1,
            Connecting = 2,
            WaitingForAuthentication = 3,
        }

        /// <remarks>
        /// #define TRANS_STATUS_TRANS  0     // 正在传输
        /// #define TRANS_STATUS_DONE   1     // 传输完成
        /// #define TRANS_STATUS_ERR    2     // 传输出错
        /// </remarks>
        public enum TransferState
        {
            Transferring = 0,
            Done = 1,
            Error = 2,
        }

        /// <remarks>
        /// enum BambookKey
        /// {
        ///     BBKeyNum0 = 0, BBKeyNum1, BBKeyNum2, BBKeyNum3, BBKeyNum4,
        ///     BBKeyNum5, BBKeyNum6, BBKeyNum7, BBKeyNum8, BBKeyNum9,
        ///     BBKeyStar, BBKeyCross, BBKeyUp, BBKeyDown, BBKeyLeft, BBKeyRight, BBKeyPageUp, BBKeyPageDown,
        ///     BBKeyOK, BBKeyESC, BBKeyBookshelf, BBKeyStore, BBKeyTTS, BBKeyMenu, BBKeyInteract
        /// };        /// </remarks>
        public enum Key
        {
            Num0 = 0,
            Num1,
            Num2,
            Num3,
            Num4,
            Num5,
            Num6,
            Num7,
            Num8,
            Num9,
            Star,
            Cross,
            Up,
            Down,
            Left,
            Right,
            PageUp,
            PageDown,
            OK,
            Esc,
            Bookshelf,
            Store,
            Tts,
            Menu,
            Interact
        }

        /// <remarks>
        /// struct DeviceInfo
        /// {
        ///     uint32_t cbSize;              // 结构大小
        ///     char sn[20];                  // 设备序列号
        ///     char firmwareVersion[20];     // 设备固件版本
        ///     uint32_t deviceVolume;        // 设备总存储空间，单位为KB
        ///     uint32_t spareVolume;         // 剩余存储空间，单位为KB
        /// };
        /// </remarks>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct DeviceInfo
        {
            [MarshalAs(UnmanagedType.U4)]
            public int SizeInBytes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string SerialNumber;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string FirmwareVersoin;
            [MarshalAs(UnmanagedType.U4)]
            public int DeviceVolume;
            [MarshalAs(UnmanagedType.U4)]
            public int SpareVolume;
        }

        /// <remarks>
        /// struct PrivBookInfo
        /// {
        ///     uint32_t cbSize;              // 结构大小
        ///     char bookGuid[20];            // 书籍id(在设备里的snb文件名)
        ///     char bookName[80];            // 书名
        ///     char bookAuthor[40];          // 作者
        ///     char bookAbstract[256];       // 摘要
        /// };
        /// </remarks>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct PrivateBookInfo
        {
            [MarshalAs(UnmanagedType.U4)]
            public int SizeInBytes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string Guid;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string Name;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
            public string Author;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string Abstract;
        }

        /// <remarks>
        /// typedef void(* TransCallback)(uint32_t status, uint32_t progress, intptr_t userData);
        /// </remarks>
        public delegate void TransferCallback(
            [MarshalAs(UnmanagedType.U4)] TransferState status,
            [MarshalAs(UnmanagedType.U4)] int progress,
            [MarshalAs(UnmanagedType.I4)] int userData);

        /// <remarks>
        /// extern "C" BB_RESULT BambookGetSDKVersion(uint32_t * version);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookGetSDKVersion",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result GetSDKVersion(
            [MarshalAs(UnmanagedType.U4), Out] out int version);

        /// <remarks>
        /// extern "C" BB_RESULT BambookConnect(const char * lpszIP, uint32_t timeOut, BB_HANDLE * hConn);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookConnect",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result Connect(
            [MarshalAs(UnmanagedType.LPStr), In] string lpszIP,
            [MarshalAs(UnmanagedType.U4), In]    int timeout,
            [MarshalAs(UnmanagedType.I4), Out]   out int hConn);

        /// <remarks>
        /// extern "C" BB_RESULT BambookDisconnect(BB_HANDLE hConn);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookDisconnect",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result Disconnect(
            [MarshalAs(UnmanagedType.I4), In] int hConn);

        /// <remarks>
        /// extern "C" BB_RESULT BambookGetConnectStatus(BB_HANDLE hConn, uint32_t * status);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookGetConnectStatus",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result GetConnectStatus(
            [MarshalAs(UnmanagedType.I4), In]  int hConn,
            [MarshalAs(UnmanagedType.U4), Out] out ConnectionState status);

        /// <remarks>
        /// extern "C" BB_RESULT BambookGetDeviceInfo(BB_HANDLE hConn, DeviceInfo * pInfo);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookGetDeviceInfo",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result GetDeviceInfo(
            [MarshalAs(UnmanagedType.I4), In]            int hConn,
            [MarshalAs(UnmanagedType.Struct), In, Out] ref DeviceInfo pInfo);

        /// <remarks>
        /// extern "C" BB_RESULT BambookGetFirstPrivBookInfo(BB_HANDLE hConn, PrivBookInfo * pInfo);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookGetFirstPrivBookInfo",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result GetFirstPrivateBookInfo(
            [MarshalAs(UnmanagedType.I4), In]          int hConn,
            [MarshalAs(UnmanagedType.Struct), In, Out] ref PrivateBookInfo pInfo);

        /// <remarks>
        /// extern "C" BB_RESULT BambookGetNextPrivBookInfo(BB_HANDLE hConn, PrivBookInfo * pInfo);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookGetNextPrivBookInfo",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result GetNextPrivateBookInfo(
            [MarshalAs(UnmanagedType.I4), In]          int hConn,
            [MarshalAs(UnmanagedType.Struct), In, Out] ref PrivateBookInfo pInfo);

        /// <remarks>
        /// extern "C" BB_RESULT BambookAddPrivBook(BB_HANDLE hConn, const char * pszSnbFile,
        ///                                         TransCallback pCallbackFunc, intptr_t userData);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookAddPrivBook",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result AddPrivateBook(
            [MarshalAs(UnmanagedType.I4), In]          int hConn,
            [MarshalAs(UnmanagedType.LPStr), In]       string pszSnbFile,
            [MarshalAs(UnmanagedType.FunctionPtr), In] TransferCallback pCallbackFunc,
            [MarshalAs(UnmanagedType.I4), In]          int userData);

        /// <remarks>
        /// extern "C" BB_RESULT BambookReplacePrivBook(BB_HANDLE hConn, const char * pszSnbFile, const char * lpszBookID,
        ///                                             TransCallback pCallbackFunc, intptr_t userData);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookReplacePrivBook",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result ReplacePrivateBook(
            [MarshalAs(UnmanagedType.I4), In]          int hConn,
            [MarshalAs(UnmanagedType.LPStr), In]       string pszSnbFile,
            [MarshalAs(UnmanagedType.LPStr), In]       string lpszBookID,
            [MarshalAs(UnmanagedType.FunctionPtr), In] TransferCallback pCallbackFunc,
            [MarshalAs(UnmanagedType.I4), In]          int userData);

        /// <remarks>
        /// extern "C" BB_RESULT BambookDeletePrivBook(BB_HANDLE hConn, const char * lpszBookID);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookDeletePrivBook",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result DeletePrivateBook(
            [MarshalAs(UnmanagedType.I4), In]    int hConn,
            [MarshalAs(UnmanagedType.LPStr), In] string lpszBookID);

        /// <remarks>
        /// extern "C" BB_RESULT BambookFetchPrivBook(BB_HANDLE hConn, const char * lpszBookID, const char * lpszFilePath,
        ///                                           TransCallback pCallbackFunc, intptr_t userData);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookFetchPrivBook",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result FetchPrivateBook(
            [MarshalAs(UnmanagedType.I4), In]          int hConn,
            [MarshalAs(UnmanagedType.LPStr), In]       string lpszBookID,
            [MarshalAs(UnmanagedType.LPStr), In]       string lpszFilePath,
            [/*MarshalAs(UnmanagedType.FunctionPtr), */In] TransferCallback pCallbackFunc,
            [MarshalAs(UnmanagedType.I4), In]          int userData);

        /// <remarks>
        /// extern "C" BB_RESULT BambookKeyPress(BB_HANDLE hConn, BambookKey key);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookKeyPress",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result KeyPress(
            [MarshalAs(UnmanagedType.I4), In] int hConn,
            [MarshalAs(UnmanagedType.I4), In] Key key);

        /// <remarks>
        /// extern "C" BB_RESULT BambookPackSnbFromDir(const char * snbName, const char * rootDir);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookPackSnbFromDir",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result PackSnbFromDirectory(
            [MarshalAs(UnmanagedType.LPStr), In] string snbName,
            [MarshalAs(UnmanagedType.LPStr), In] string rootDir);

        /// <remarks>
        /// extern "C" BB_RESULT BambookUnpackFileFromSnb(const char * snbName, const char * relativePath, const char * outputName);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookUnpackFileFromSnb",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result UnpackFileFromSnb(
            [MarshalAs(UnmanagedType.LPStr), In] string snbName,
            [MarshalAs(UnmanagedType.LPStr), In] string relativePath,
            [MarshalAs(UnmanagedType.LPStr), In] string outputName);

        /// <remarks>
        /// extern "C" BB_RESULT BambookVerifySnbFile(const char * snbName);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookVerifySnbFile",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        public static extern Result VerifySnbFile(
            [MarshalAs(UnmanagedType.LPStr), In] string snbName);

        /// <remarks>
        /// extern "C" const char * BambookGetErrorString(BB_RESULT nCode);
        /// </remarks>
        [DllImport("BambookCore.dll",
            EntryPoint = "BambookGetErrorString",
            CallingConvention = CallingConvention.Cdecl,
            CharSet = CharSet.Ansi,
            ExactSpelling = true,
            PreserveSig = true)]
        [return: MarshalAs(UnmanagedType.LPStr)]
        public static extern string GetErrorString(
            [MarshalAs(UnmanagedType.I4), In] Result nCode);
    }
}
